package smartfleet.mobile;


import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;

import smartfleet.mobile.Protocol.Station;
import smartfleet.mobile.Protocol.Traveller;
import smartfleet.mobile.Protocol.Trip;
import smartfleet.mobile.Protocol.location;
import smartfleet.mobile.rest.webservice.vehicle.VehicleWebServiceUtil;
import smartfleet.mobile.vehicle.Vehicle;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;

public class mobile extends MapActivity {
	
	private int _id;

	private RegisterValues reg_values = new RegisterValues();

	public static final int Near_Entity = 1;
	public static final int Changes = 2; 
	public static final int RecievedTrip = 3;
	public static final int Charge = 4;
	public static final int Charged = 5;
	public static final int Destination = 6;
	
	MyLocationOverlay myLocationOverlay;
	
	MapController mc;
	
	Vehicle thisVehicle;

	Destination nextDestination = null;
	
	Queue<Destination> destinationQueue = new LinkedList<Destination>();

	/** TextViews **/
	private TextView dest_text;
	private TextView alt_text;
	private TextView batt_text;
	
	private Trip.Builder trip;
	
	Messenger mBoundSim;
	private Boolean SimIsBound = false;
	
	Dialog destination_dialog;
	Dialog charge_dialog;
	
	private dbAdapter mDbHelper;
	private boolean mDbisOpen = false;
	
	private boolean init = false;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.main);

        /** Apenas para zoom **/
        MapView mapView = (MapView) findViewById(R.id.mapview);
        mapView.setBuiltInZoomControls(true);
        
        mc = mapView.getController();
        
        mc.setZoom(15);
 
        myLocationOverlay = new MyLocationOverlay(this, mapView);
        mapView.getOverlays().add(myLocationOverlay);
        myLocationOverlay.enableCompass();
        myLocationOverlay.enableMyLocation();
        
        /** Create destination dialog **/
        createDialog();
        
        /** Initiate activity to collect id and port **/
        Intent i = new Intent(this, initial.class);
        startActivityForResult(i, 1);
        
        
        /** Find textViews **/
        dest_text = (TextView) findViewById(R.id.dest_text);
        alt_text = (TextView) findViewById(R.id.alt);
        batt_text = (TextView) findViewById(R.id.batt_text);
        
        /** Create database **/
        mDbHelper = new dbAdapter(this);
        
        final Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
            	
            	try {
					mBoundSim.send(Message.obtain(null, SimService.Reset_Battery));
					mDbHelper.setBattery(0);
            		Toast.makeText(mobile.this, "OUT OF BATTERY", Toast.LENGTH_LONG).show();

				} catch (RemoteException e) {
					e.printStackTrace();
				}       
            }
        });
        
        /** Teste **/
        
        final Button button2 = (Button) findViewById(R.id.bd_button);
        button2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
            	RecievedTrip(trip.build());
            	//mDbHelper.printDB();
            }
        });
        
        
        /*******************************************************************/
        
        LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        
        LocationListener locationListener = new LocationListener() {
        	
            public void onLocationChanged(Location location) {
            	
            	update(location);
            	
            }

            public void onStatusChanged(String provider, int status, Bundle extras) {}

            public void onProviderEnabled(String provider) {}

            public void onProviderDisabled(String provider) {}
          };

        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
        
        /** Teste **/
        
Trip.Builder testing = Trip.newBuilder();
        
        testing.setId(1);
        
        Station.Builder stat = Station.newBuilder();
        
        
        location.Builder loc1 = location.newBuilder();
        loc1.setLon(-9.13831);
        loc1.setLat(38.736762);
        loc1.setName("IST-Alameda");
        
        stat.setLocation(loc1);
        stat.setId(2);
        //stat.setName("IST-Alameda");
        
        
        Traveller.Builder trav1 = Traveller.newBuilder();
        trav1.setId(1);
        trav1.setName("João");
        
        Date a = new Date(2011,12,12,8,20,30);
        
        trav1.setCheckin(a.getTime());
        trav1.setSize(2);
        trav1.setState("onBoard");
        trav1.setCheckin(System.currentTimeMillis());
        trav1.setCheckout(0);
      
        loc1 = location.newBuilder();
        loc1.setLon(-9.1318703);
        loc1.setLat(38.7381177);
        loc1.setName("loc1");
        
        
        
        
        trav1.setDestination(loc1);
        trav1.setStation(stat);
        
        testing.addTravellers(trav1);
        
        stat = Station.newBuilder();
        
        
        loc1 = location.newBuilder();
        loc1.setLon(-9.13831);
        loc1.setLat(38.736762);
        loc1.setName("IST-Alameda");
        
        stat.setLocation(loc1);
        stat.setId(2);
        //stat.setName("IST-Alameda");
        
        
        Traveller.Builder trav2 = Traveller.newBuilder();
        trav2.setId(2);
        trav2.setName("Antonio");
        trav2.setCheckin(a.getTime());
        trav2.setSize(1);
        trav2.setState("onBoard");
        trav2.setCheckin(System.currentTimeMillis());
        trav2.setCheckout(0);
        
        location.Builder loc2 = location.newBuilder();
        loc2.setLon(-9.1353893);
        loc2.setLat(38.7398249);
        loc2.setName("loc2");
        
        trav2.setDestination(loc2);
        trav2.setStation(stat);
        testing.addTravellers(trav2);
        
        stat = Station.newBuilder();
        
        
        loc1 = location.newBuilder();
        loc1.setLon(-9.13831);
        loc1.setLat(38.736762);
        loc1.setName("IST-Alameda");
        
        stat.setLocation(loc1);
        stat.setId(2);
        //stat.setName("IST-Alameda");
        
        Traveller.Builder trav3 = Traveller.newBuilder();
        trav3.setId(3);
        trav3.setName("Zelmira");
        trav3.setCheckin(a.getTime());
        trav3.setSize(1);
        trav3.setState("onBoard");
        trav3.setCheckin(System.currentTimeMillis());
        trav3.setCheckout(0);
        
        
        location.Builder loc3 = location.newBuilder();
        loc3.setLon(-9.1333723);
        loc3.setLat(38.7370465);
        loc3.setName("loc3");
        
        trav3.setDestination(loc3);
        trav3.setStation(stat);
        testing.addTravellers(trav3);
        
        /* Last destination **/
        
        stat = Station.newBuilder();
        
        loc1 = location.newBuilder();
        loc1.setLon(-9.128523);
        loc1.setLat(38.771149);
        
        loc1.setName("IST-Alameda");
        
        stat.setLocation(loc1);
        stat.setId(2);
        
        testing.setLastDestination(stat);
        
        trip = testing;
        
        
    }
    
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {

        	mBoundSim = new Messenger(service);
        	
            Message msg = Message.obtain(null, SimService.Register_Mobile, reg_values);
            msg.replyTo = mMessenger;
            
            Message msg2 = Message.obtain(null, SimService.Send_DB, 0, 0, mDbHelper);
            
            try {
				mBoundSim.send(msg);
				mBoundSim.send(msg2);
			} catch (RemoteException e) {
				e.printStackTrace();
			}

            SimIsBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
        	mBoundSim = null;
        	SimIsBound = false;
        }
    };

    void doBindService() {
        
        bindService(new Intent(this, SimService.class), mConnection, Context.BIND_AUTO_CREATE);
    }

    void doUnbindService() {
        if (SimIsBound) {

            unbindService(mConnection);
        }
    }
    
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case Near_Entity:
                	Toast.makeText(mobile.this, (String) msg.obj, Toast.LENGTH_SHORT).show();
                    break;
                case Changes:
                	alt_text.setText("Alt: "+msg.arg2+"m");
                	writeBaterry(msg.arg1);
                	if(msg.arg1 < 10){

                		Toast.makeText(mobile.this, "OUT OF BATTERY", Toast.LENGTH_LONG).show();
                		
                	}
                	break;
                case RecievedTrip:
                	Trip a = (Trip) msg.obj;
                	RecievedTrip(a);
                	break;
                
                case Charge:
                	charge_dialog.show();
                	new ChargeThread(msg.arg1, mMessenger).start();
                	break;
                case Charged:
                	charge_dialog.dismiss();
                	writeBaterry(msg.arg1);
					try {
						mBoundSim.send(Message.obtain(null, SimService.Charged));
					} catch (RemoteException e) {
	
						e.printStackTrace();
					}
                	break;
                case Destination:
                	Start(destinationQueue.poll());
                	break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    
    
    final Messenger mMessenger = new Messenger(new IncomingHandler());
    
    @Override
    protected void onStart() {
        super.onStart();
        

        if(init){

        	/** Bind simulator Service **/
            doBindService();
        	
        	/** Open database **/
        	mDbHelper.open(_id);
            mDbisOpen = true;

            System.out.println("initVeicule");
            mDbHelper.initiateVehicle(reg_values.getBattery(), "onStation", 0, 4);

            VehicleWebServiceUtil.registerOrUpdateVehicleInfo(mDbHelper.getVehicle());

            
        	Toast.makeText(this, "Vehicle Initialized", Toast.LENGTH_SHORT).show();
        }
        
    }
    
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        Bundle extras = intent.getExtras();
        
        _id = Integer.parseInt(extras.getString("id"));
        reg_values.set_id(_id);
        reg_values.set_netport(Integer.parseInt(extras.getString("netport")));
        reg_values.set_emulport(Integer.parseInt(extras.getString("emulport")));
        reg_values.set_sim_addr(extras.getString("sim_addr"));
        reg_values.set_sim_port(Integer.parseInt(extras.getString("sim_port")));
        reg_values.set_station_id(Integer.parseInt(extras.getString("station_id")));
        reg_values.setBattery(Integer.parseInt(extras.getString("battery")));
        
        writeBaterry(reg_values.getBattery());
        
        init = true;

    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        
        
        try {
        	
			mBoundSim.send(Message.obtain(null, SimService.Unregister_Mobile, _id, 0));
			
		} catch (RemoteException e) {
			e.printStackTrace();
		}
        
        doUnbindService();
        
        mDbisOpen = false;
        mDbHelper.close();
    }
    
    
    private void Start(Destination dest){
    	
    	mDbHelper.setState("Moving");
    	setDestination(dest);
    	Message msg = Message.obtain(null, SimService.Mobile_Move, dest.getLocation());
    	try {
			mBoundSim.send(msg);
		} catch (RemoteException e) {
			e.printStackTrace();
		}

    	dest_text.setText(dest.getLocation().getProvider());
    	
    }
    
    private void Stop(){
    	
    	mDbHelper.setState("Stopped");
    	dest_text.setText("NONE");
    	nextDestination = null;
    }
    
    
    private void setDestination(Destination dest){
	
    	nextDestination = dest;
	
    	mDbHelper.setDestination(dest.getLocation().getProvider(), dest.getLocation());

    }
    
    /** Update in each location change **/
    public void update(Location current){
    	
    	/** Follow current position on map**/
    	mc.animateTo(myLocationOverlay.getMyLocation());
    	
    	if(mDbisOpen)
    		mDbHelper.setVehicleLocation(current);
    	
    	if(nextDestination != null){
    		
    		if(current.distanceTo(nextDestination.getLocation()) < 5){
        		
        		if(!destinationQueue.isEmpty()){
        			
        			mDbHelper.checkoutTraveller(nextDestination.getID(), System.currentTimeMillis());
            		
            		removeTableRow();
            		setDialogText(nextDestination.getName(), nextDestination.getLocation().getProvider());
        			destination_dialog.show();
        			dialogThread dialog_thread = new dialogThread(5000, mMessenger);
        			dialog_thread.start();
        			
        		}
        		
        		Stop();
        		
        	}

    	}
    }
    
    private void RecievedTrip(Trip t){
    	
    	mDbHelper.setTrip(t);
    	
    	Location loc;
    	
    	Destination dest;
    	
    	Date time = new Date();
    	time.setMinutes(0);
    	time.setSeconds(0);
    	
    	Location locTime = mDbHelper.getVehicleLocation();
    	
    	int to_increment;
    	boolean flag = true;
    	
    	for(Traveller a : t.getTravellersList()){
    		
    		loc = new Location(a.getDestination().getName());
    		loc.setLongitude(a.getDestination().getLon());
    		loc.setLatitude(a.getDestination().getLat());
    		
    		to_increment = (int) loc.distanceTo(locTime)/10;
    		
    		if(flag){
    			time.setSeconds(time.getSeconds()+to_increment);
    			flag = false;
    		}
    		else
    			time.setSeconds(time.getSeconds()+to_increment+60);
    		
    		locTime = loc;
    		
    		dest = new Destination(a.getId(), a.getName(), loc);
    		
    		destinationQueue.offer(dest);
    		
    		insertOnTable(a.getName(), a.getDestination().getName(), time.getHours()+":"+time.getMinutes()+":"+time.getSeconds());
    		
    	}
    	
    	Station last_dest = t.getLastDestination();
    	
    	loc = new Location(last_dest.getLocation().getName());
    	loc.setLongitude(last_dest.getLocation().getLon());
    	loc.setLatitude(last_dest.getLocation().getLat());
    	
    	dest = new Destination(loc);
    	
    	destinationQueue.offer(dest);
    	
    	dialogThread dialog_thread = new dialogThread(5000, mMessenger);
		dialog_thread.start();
    }
    
    private void createDialog(){
    	
    	 destination_dialog = new Dialog(this);
         destination_dialog.setContentView(R.layout.destination_dialog);
         charge_dialog = new Dialog(this);
         charge_dialog.setContentView(R.layout.charge_dialog);
    	
    }
    
    private void setDialogText(String name, String address){
    	
    	destination_dialog.setTitle(name);
    	TextView text = (TextView) destination_dialog.findViewById(R.id.text);
    	text.setText("You reached "+address+"!");
    }
    
    private void insertOnTable(String party, String dest, String time)
    {

        TableLayout tl = (TableLayout)findViewById(R.id.table);

             TableRow tr = new TableRow(this);

             TextView text1 = new TextView(this);
             TextView text2 = new TextView(this);
             TextView text3 = new TextView(this);
             
             text1.setText(party);
             text1.setGravity(Gravity.CENTER);
             text2.setText(dest);
             text2.setGravity(Gravity.CENTER);
             text3.setText(time);
             text3.setGravity(Gravity.CENTER);

             tr.addView(text1);
             tr.addView(text2);
             tr.addView(text3);

        tl.addView(tr);
    	
    }
    
    private void writeBaterry(int batt){
    	
    	batt = batt*100/36000;
    	batt_text.setText("Batt: "+batt+"%");
    }
    
    private void removeTableRow(){
    	
    	TableLayout tl = (TableLayout)findViewById(R.id.table);
    	if(tl.getChildAt(1) != null)
    		tl.removeViewAt(1);
    }
    
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
    
    private class dialogThread extends Thread {
    	
    	long _time;
    	Messenger _messenger;
    	
        dialogThread(long time, Messenger msg) {
        	_time = time;
        	_messenger = msg;
        }
       
        public void run() {
        		try {
        			
					Thread.sleep(_time);
					destination_dialog.dismiss();
					_messenger.send(Message.obtain(null, Destination));
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (RemoteException e) {
					e.printStackTrace();
				}
        }
    }
    
    class ChargeThread extends Thread{
    
    	int _limit;
    	
    	Messenger _messenger;
    	
    	ChargeThread(int limit, Messenger msg) {
    		_limit = limit;
    		_messenger = msg;
        }
       
        public void run() {
        	long time = 5000; //TODO (_limit - mDbHelper.getBattery())*100;
        	try {
				Thread.sleep(time);
				mDbHelper.setBattery(_limit);
				_messenger.send(Message.obtain(null, Charged,_limit, 0));
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (RemoteException e) {
				e.printStackTrace();
			}
        	
        }
    	
    }
}